package verify

import (
	"fmt"
	"reflect"

	"github.com/go-playground/validator/v10"
)

var validate = validator.New()

// 辅助函数：判断是否是切片/数组类型
func isSliceOrArray(fieldError validator.FieldError) bool {
	t := fieldError.Type()
	return t.Kind() == reflect.Slice || t.Kind() == reflect.Array
}

// 辅助函数：判断是否是结构体类型
func isStruct(fieldError validator.FieldError) bool {
	return fieldError.Type().Kind() == reflect.Struct
}

// 新增：通用验证错误处理函数
// 新增验证场景说明：
// 1. email ：处理邮箱格式验证（如 validate:"email" ）
// 2. len ：处理固定长度验证（如 validate:"len=11" 用于手机号）
// 3. gte ：处理大于等于验证（如 validate:"gte=0" 用于非负数）
// 4. lte ：处理小于等于验证（如 validate:"lte=100" 用于百分比）
// 5. alphanum ：处理字母数字组合验证（如 validate:"alphanum" 用于用户名）
// 6. url ：处理URL格式验证（如 validate:"url" 用于链接字段）
// 7. numeric ：处理纯数字验证（如 validate:"numeric" 用于编号字段）
// 8. contains ：处理包含子串验证（如 validate:"contains=abc" ）
// 9. excludes ：处理排除子串验证（如 validate:"excludes=abc" ）
// - 对象/数组非空 ：通过 required 标签+类型判断，区分普通字段/数组/对象的空值提示（如"UserInfo对象不能为空"、"Hobbies数组不能为空"）
// - 数组长度限制 ： min / max 标签作用于数组时，明确提示"数组长度不能小于/大于X"
// - 数组元素唯一性 ： unique 标签处理重复元素（如"Tags数组中存在重复元素"）
// - 值枚举校验 ： oneof 标签限制值范围（如"Status值必须是以下之一: draft,published"）
// - 字符串起止校验 ： startswith / endswith 处理前缀后缀（如"FileName必须以子串'img_'开头"）
// - 网络地址校验 ： ip / ipv4 / ipv6 / mac 处理网络相关格式
// - 标准格式校验 ： uuid / base64 处理通用编码格式

// type User struct {
//     ID        string   `validate:"required,uuid"`          // UUID格式且非空
//     Name      string   `validate:"required,alphanum"`      // 非空且仅字母数字
//     Roles     []string `validate:"required,min=1,unique"`  // 非空数组（至少1个元素）且无重复
//     Email     string   `validate:"required,email"`         // 非空邮箱格式
//     AvatarURL string   `validate:"required,url"`           // 非空URL格式
//     Age       int      `validate:"gte=0,lte=150"`          // 年龄0-150岁
//     Group     Group    `validate:"required"`               // 非空对象
// }

// type Group struct {
//     Code string `validate:"required,startswith=GRP-"`      // 非空且以"GRP-"开头
// }

func processValidationErrors(errors validator.ValidationErrors) error {
	for _, fieldError := range errors {
		switch fieldError.Tag() {
		case "required":
			if isSliceOrArray(fieldError) {
				return fmt.Errorf("%s数组不能为空", fieldError.Field())
			} else if isStruct(fieldError) {
				return fmt.Errorf("%s对象不能为空", fieldError.Field())
			}
			return fmt.Errorf("%s不能为空", fieldError.Field())
		case "email":
			return fmt.Errorf("%s不是有效的邮箱地址", fieldError.Field())
		case "len":
			// 由于 fieldError.Param() 返回的是 string 类型，而 %d 需要 int 类型，因此改为 %s 以匹配参数类型
			return fmt.Errorf("%s长度必须为%s", fieldError.Field(), fieldError.Param())
		case "gte":
			return fmt.Errorf("%s必须大于或等于%s", fieldError.Field(), fieldError.Param())
		case "lte":
			return fmt.Errorf("%s必须小于或等于%s", fieldError.Field(), fieldError.Param())
		case "alphanum":
			return fmt.Errorf("%s只能包含字母和数字", fieldError.Field())
		case "url":
			return fmt.Errorf("%s不是有效的URL地址", fieldError.Field())
		case "numeric":
			return fmt.Errorf("%s只能包含数字", fieldError.Field())
		case "contains":
			return fmt.Errorf("%s必须包含子串'%s'", fieldError.Field(), fieldError.Param())
		case "excludes":
			return fmt.Errorf("%s不能包含子串'%s'", fieldError.Field(), fieldError.Param())
		case "min":
			return fmt.Errorf("%s长度不能小于%s", fieldError.Field(), fieldError.Param())
		case "max":
			return fmt.Errorf("%s长度不能大于%s", fieldError.Field(), fieldError.Param())
		case "unique":
			return fmt.Errorf("%s数组中存在重复元素", fieldError.Field())
		case "oneof":
			return fmt.Errorf("%s值必须是以下之一: %s", fieldError.Field(), fieldError.Param())
		case "startswith":
			return fmt.Errorf("%s必须以子串'%s'开头", fieldError.Field(), fieldError.Param())
		case "endswith":
			return fmt.Errorf("%s必须以子串'%s'结尾", fieldError.Field(), fieldError.Param())
		case "ip":
			return fmt.Errorf("%s不是有效的IP地址", fieldError.Field())
		case "ipv4":
			return fmt.Errorf("%s不是有效的IPv4地址", fieldError.Field())
		case "ipv6":
			return fmt.Errorf("%s不是有效的IPv6地址", fieldError.Field())
		case "mac":
			return fmt.Errorf("%s不是有效的MAC地址", fieldError.Field())
		case "uuid":
			return fmt.Errorf("%s不是有效的UUID格式", fieldError.Field())
		case "base64":
			return fmt.Errorf("%s不是有效的Base64编码", fieldError.Field())
		case "json":
			return fmt.Errorf("%s不是有效的JSON格式", fieldError.Field())
		case "xml":
			return fmt.Errorf("%s不是有效的XML格式", fieldError.Field())
		case "yaml":
			return fmt.Errorf("%s不是有效的YAML格式", fieldError.Field())
		case "toml":
			return fmt.Errorf("%s不是有效的TOML格式", fieldError.Field())
		case "ini":
			return fmt.Errorf("%s不是有效的INI格式", fieldError.Field())
		case "csv":
			return fmt.Errorf("%s不是有效的CSV格式", fieldError.Field())
		case "xmlpath":
			return fmt.Errorf("%s不是有效的XML路径", fieldError.Field())
		case "jsonpath":
			return fmt.Errorf("%s不是有效的JSON路径", fieldError.Field())

		}
		// 通用错误处理
		return fmt.Errorf("字段 %s 的值 %v 不符合验证规则: %s", fieldError.Field(), fieldError.Value(), fieldError.Tag())
	}
	return nil
}

func ValidateStruct(data any, except ...string) error {
	if except == nil {
		except = []string{}
	}
	if err := validate.StructExcept(data, except...); err != nil {
		if validationErrors, ok := err.(validator.ValidationErrors); ok {
			return processValidationErrors(validationErrors)
		}
		return fmt.Errorf("验证失败")

	} else {
		return nil
	}

}
